package gbench.sandbox.record;

import org.junit.jupiter.api.Test;
import lombok.Data;

import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import gbench.common.tree.LittleTree;
import gbench.common.tree.LittleTree.IRecord;
import gbench.common.tree.LittleTree.Node;

import static gbench.common.tree.LittleTree.IRecord.*;

/**
 * 
 * @author gbench
 *
 */
public class JunitRecordTree {
    
    /**
     * 周期模型
     * @author gbench
     *
     * @param <T> 周围模型的所有者
     */
    public static class PeriodicCycleModel<T> {
        /**
         * 
         * @param interval
         */
        public PeriodicCycleModel(T owner,Number interval) {
            this.owner = owner;
            this.interval = interval.longValue();
            this.counter = new AtomicLong(0l);
        }
        
        /**
         * 周期模型
         * 
         * @return
         */
        public PeriodicCycleModel<T> restart(BiConsumer<T, Event> cs) {
            new Thread(() -> {
                while (!stopFlag) {
                    cs.accept(owner, this.new Event(counter.getAndIncrement()));
                    try {
                        Thread.sleep(this.interval);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }//while
            }).start();
            return this;
        }

        /**
         * 
         * @return
         */
        public PeriodicCycleModel<T> stop(){
            this.stopFlag = true;
            return this;
        }
        
        @Data
        public class Event{
            /**
             * 
             * @param id
             */
            public Event(long id){
                this.id = id;
                this.name = id+"";
            }
            private long id;
            private String name;
        }
        
        private AtomicLong counter;
        private final long interval ;
        private boolean stopFlag = false;
        private T owner;
    }
    
    /**
     * 
     * @author gbench
     *
     */
    public interface ISociety{
        public String getName();
        public ISociety initialize(Number m,Number n);
        public ISociety restart(BiConsumer<ISociety,PeriodicCycleModel<ISociety>.Event> cs);
    }
    
    /**
     * 
     * @author gbench
     *
     */
    public class Society implements ISociety{
        
        /**
         * 
         * @param name
         * @param interval
         */
        public Society(String name,int interval){
            this.name = name;
            cycleModel = new PeriodicCycleModel<>(this,interval);
        }
        
        @Override
        public String getName() {
            return name;
        }

        @Override
        public Society initialize(Number m, Number n) {
            return this;
        }

        @Override
        public ISociety restart(BiConsumer<ISociety,PeriodicCycleModel<ISociety>.Event> cs) {
            cycleModel.restart(cs);
            return this;
        }
        
        public String toString() {
            return name;
        }
        
        //15000132549
        private String name;
        PeriodicCycleModel<ISociety> cycleModel;
    }
    
    
    /**
     * 结构化一个Society
     * @author gbench
     *
     */
    public class Society2 extends Node<IRecord> implements ISociety{
        
        /**
         * 构造函数
         * @param node
         */
        public Society2(Node<IRecord> node) {
            super(node.getValue());
        }
        
        /**
         * 
         * @return
         */
        public Society2 parent() {
            return new Society2(this.getParent());
        }
        
        /**
         * 
         * @return
         */
        public List<Society2> children() {
            return this.getChildren().stream().map(Society2::new).collect(Collectors.toList());
        }
        
        /**
         * 
         * @return
         */
        public ISociety society() {
            return this.getValue(e->e.get("society",Society.class));
        }
        
        /**
         * 
         * @return
         */
        public ISociety society(String path) {
            return this.get(path).getValue(e->e.get("society",Society.class));
        }

        @Override
        public ISociety initialize(Number m, Number n) {
            return this.society().initialize(m, n);
        }

        @Override
        public ISociety restart(BiConsumer<ISociety, PeriodicCycleModel<ISociety>.Event> cs) {
            return this.society().restart(cs);
        }
        
        /**
         * 
         * @param cs
         */
        public void forEach2(Consumer<Society2>cs) {
            this.forEach(e->{
                cs.accept(new Society2(e));;
            });
        }
        
    }
    
    /**
     * 展示IRecord 构造一个树形结构
     * @throws InterruptedException
     */
    @Test
    public void foo() throws InterruptedException {
        
        final var hierachies = L( //  hierachies
           "0   中国          -",
           
           "1   北京          0",
           "1.1   东城区          1",
           
           "2   上海          0",
           "2。1   长宁区          2",
           
           "3   天津          0",
           "4   重庆          0"
        );
        
        // id name pid 列表
        final var builder = IRecord.builder("id,name,pid");
        final var tree = hierachies.stream()
            .map(line->line.split("\\s+"))
            .map(builder::get)
            .map(e->e.add("society",new Society(e.str("name"),1000)))// 增加字段 Society 
            .collect(llclc(recs->LittleTree.buildTree2(recs, Society2::new))); // 把结果转换成Society2 类型
            
        tree.forEach(node->{
            System.out.println("\t".repeat(node.getLevel())+node);
        });
        
        tree.forEach2(society->{
            society.restart((s,e)->{
                System.out.println(s.getName()+""+e);
            });
        });
        
        // 社会的层级演示
        Thread.sleep(10000);
    }

}
